package org.finesys.codegen.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.finesys.codegen.entity.GenDatasourceConf;
import org.finesys.codegen.mapper.GenDatasourceConfMapper;
import org.finesys.codegen.service.GenDatasourceConfService;
import org.finesys.common.core.util.SpringContextHolder;
import org.finesys.common.database.core.enums.DsConfTypeEnum;
import org.finesys.common.database.core.enums.DsJdbcUrlEnum;
import org.finesys.common.mp.core.service.impl.BaseServiceImpl;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Arrays;

@Service
@RequiredArgsConstructor
@Slf4j
public class GenDatasourceConfServiceImpl extends BaseServiceImpl<GenDatasourceConfMapper, GenDatasourceConf> implements GenDatasourceConfService {
    //加密工具类
    private final StringEncryptor stringEncryptor;
    //数据源连接
    private final DefaultDataSourceCreator defaultDataSourceCreator;

    @Override
    public Boolean saveDsByEnc(GenDatasourceConf datasourceConf) {
        //检验合法配置
        if (!checkDataSource(datasourceConf)) {
            return Boolean.FALSE;
        }
        //添加动态数据源
        addDynamicDataSource(datasourceConf);
        //更新数据库配置
        datasourceConf.setPassword(stringEncryptor.encrypt(datasourceConf.getPassword()));
        this.baseMapper.insert(datasourceConf);
        return Boolean.TRUE;
    }

    @Override
    public Boolean removeByDsId(Long[] dsIds) {
        //先移除
        DynamicRoutingDataSource dynamicRoutingDataSource = SpringContextHolder.getBean(DynamicRoutingDataSource.class);
        //移除数据源连接
        this.baseMapper.selectBatchIds(Arrays.asList(dsIds)).forEach(ds -> dynamicRoutingDataSource.removeDataSource(ds.getAlias()));
        //删除
        this.baseMapper.deleteBatchIds(Arrays.asList(dsIds));
        return Boolean.TRUE;
    }

    @Override
    public Boolean checkDataSource(GenDatasourceConf datasourceConf) {
        //数据库类型
        String dsType = datasourceConf.getDsType();
        DsJdbcUrlEnum dsJdbcUrlEnum = DsJdbcUrlEnum.get(dsType);
        //URL
        String url;
        //JDBC连接方式
        if (DsConfTypeEnum.JDBC.getType().equals(datasourceConf.getConfType())) {
            url = datasourceConf.getUrl();
        } else {
            String host = datasourceConf.getHost();
            int port = datasourceConf.getPort();
            String dsName = datasourceConf.getInstance();
            //URL重设
            url = String.format(dsJdbcUrlEnum.getUrl(), host, port, dsName);
        }
        datasourceConf.setUrl(url);
        //驱动程序赋值
        if (!StringUtils.hasText(datasourceConf.getDriverClassName())) {
            datasourceConf.setDriverClassName(dsJdbcUrlEnum.getDriverClassName());
        }
        try {
            DriverManager.getConnection(datasourceConf.getUrl(), datasourceConf.getUsername(), datasourceConf.getPassword());
        } catch (SQLException e) {
            log.error("数据源配置 {} , 获取链接失败", datasourceConf.getName(), e);
            return Boolean.FALSE;
        }


        return Boolean.TRUE;
    }

    @Override
    public Boolean updateDsByEnc(GenDatasourceConf datasourceConf) {
        //检验合法配置
        if (StringUtils.hasText(datasourceConf.getPassword()) && !checkDataSource(datasourceConf)) {
            return Boolean.FALSE;
        }
        GenDatasourceConf oldDatasourceConf = baseMapper.selectById(datasourceConf.getDsId());
        Assert.notNull(oldDatasourceConf, "数据源不存在");
        //先移除
        SpringContextHolder.getBean(DynamicRoutingDataSource.class).removeDataSource(oldDatasourceConf.getAlias());
        //密码处理
        if (StrUtil.isBlank(datasourceConf.getPassword())) {
            String password = stringEncryptor.decrypt(oldDatasourceConf.getPassword());
            datasourceConf.setPassword(password);
        }
        //添加动态数据源
        addDynamicDataSource(datasourceConf);
        // 更新数据库配置
        datasourceConf.setPassword(stringEncryptor.encrypt(datasourceConf.getPassword()));
        this.baseMapper.updateById(datasourceConf);
        return Boolean.TRUE;
    }

    @Override
    public void addDynamicDataSource(GenDatasourceConf datasourceConf) {
        DataSourceProperty dataSourceProperty = new DataSourceProperty();
        dataSourceProperty.setPoolName(datasourceConf.getAlias());
        dataSourceProperty.setUrl(datasourceConf.getUrl());
        if (StringUtils.hasText(datasourceConf.getDriverClassName())) {
            dataSourceProperty.setDriverClassName(datasourceConf.getDriverClassName());
        }
        dataSourceProperty.setUsername(datasourceConf.getUsername());
        dataSourceProperty.setPassword(datasourceConf.getPassword());
        dataSourceProperty.setLazy(true);
        DataSource dataSource = defaultDataSourceCreator.createDataSource(dataSourceProperty);
        SpringContextHolder.getBean(DynamicRoutingDataSource.class).addDataSource(dataSourceProperty.getPoolName(), dataSource);
    }
}
